package com.tbynet.jwp.framework.core;

import com.jfinal.plugin.activerecord.Page;
import java.util.List;
import java.util.Map;

/**
 * 通用服务接口 - 支持复合主键和多样化查询
 *
 * 设计原则：
 * - 单一职责：每个方法只负责一个明确的数据访问操作
 * - 无状态：不包含业务逻辑，只提供数据访问能力
 * - 完整性：提供完整的CRUD、查询、统计和存在性检查
 * - 安全性：所有方法都包含参数验证和异常处理
 *
 * 使用示例：
 * <pre>{@code
 * public class UserService extends JwpServiceProvider<User> {
 *     // 只需继承即可获得所有基础数据访问能力
 *     // 可以添加特定于User的业务方法
 * }
 * }</pre>
 *
 * @param <T> 实体类型，必须继承自JFinal的Model
 * @author 佰亿互联
 * @version 3.0
 * @since 2025-11-04
 */
public interface _JwpService<T> {

    // ========== 基础CRUD操作 ==========

    /**
     * 根据主键获取实体
     *
     * @param id 主键值，不能为null
     * @return 实体对象，未找到或参数错误时返回null
     *
     * 使用示例：
     * <pre>{@code
     * User user = userService.getById(1L);
     * if (user != null) {
     *     // 处理用户数据
     * }
     * }</pre>
     */
    T getById(Object id);

    /**
     * 根据复合主键获取实体
     *
     * @param ids 主键值数组，按数据库表定义的主键字段顺序传入
     * @return 实体对象，未找到或参数错误时返回null
     *
     * 使用示例：
     * <pre>{@code
     * // 假设UserRole表有复合主键(userId, roleId)
     * UserRole userRole = userRoleService.getByIds(1L, 2L);
     * }</pre>
     */
    T getByIds(Object... ids);

    /**
     * 保存实体到数据库
     *
     * @param entity 要保存的实体对象，不能为null
     * @return 保存成功返回true，失败返回false
     *
     * 使用示例：
     * <pre>{@code
     * User user = new User();
     * user.set("name", "张三");
     * user.set("email", "zhangsan@example.com");
     * boolean success = userService.save(user);
     * }</pre>
     */
    boolean save(T entity);

    /**
     * 更新数据库中已存在的实体
     *
     * @param entity 要更新的实体对象，必须包含有效的主键值
     * @return 更新成功返回true，失败返回false
     *
     * 使用示例：
     * <pre>{@code
     * User user = userService.getById(1L);
     * user.set("name", "李四");
     * boolean success = userService.update(user);
     * }</pre>
     */
    boolean update(T entity);

    /**
     * 根据主键删除实体
     *
     * @param id 主键值，不能为null
     * @return 删除成功返回true，失败返回false
     */
    boolean deleteById(Object id);

    /**
     * 根据复合主键删除实体
     *
     * @param ids 主键值数组，按数据库表定义的主键字段顺序传入
     * @return 删除成功返回true，失败返回false
     */
    boolean deleteByIds(Object... ids);

    /**
     * 根据ID列表批量获取实体（仅适用于单主键表）
     *
     * @param ids ID列表，不能为null但可以为空列表
     * @return 实体列表，复合主键表返回空列表
     *
     * 使用示例：
     * <pre>{@code
     * List<Object> userIds = Arrays.asList(1L, 2L, 3L);
     * List<User> users = userService.getByIdList(userIds);
     * }</pre>
     */
    List<T> getByIdList(List<Object> ids);

    // ========== 查询和搜索功能 ==========

    /**
     * 关键词搜索 - 支持分页
     *
     * @param pageNumber 页码，从1开始，自动修正非法值
     * @param pageSize 每页记录数，自动修正到合理范围
     * @param keyword 搜索关键词，为空时返回所有记录
     * @return 分页结果，异常时返回空分页
     *
     * 使用示例：
     * <pre>{@code
     * // 搜索包含"张三"的用户
     * Page<User> userPage = userService.search(1, 10, "张三");
     * }</pre>
     */
    Page<T> search(int pageNumber, int pageSize, String keyword);

    /**
     * 高级搜索 - 支持多条件组合查询
     *
     * 支持的操作符：
     * - field:like - 模糊查询
     * - field:gt - 大于
     * - field:ge - 大于等于
     * - field:lt - 小于
     * - field:le - 小于等于
     * - field:ne - 不等于
     *
     * @param pageNumber 页码
     * @param pageSize 页大小
     * @param conditions 查询条件Map
     * @return 分页结果，异常时返回空分页
     *
     * 使用示例：
     * <pre>{@code
     * Map<String, Object> conditions = new HashMap<>();
     * conditions.put("name:like", "张");     // 姓名包含"张"
     * conditions.put("age:ge", 18);         // 年龄大于等于18
     * conditions.put("status", 1);          // 状态等于1
     * Page<User> userPage = userService.advancedSearch(1, 10, conditions);
     * }</pre>
     */
    Page<T> advancedSearch(int pageNumber, int pageSize, Map<String, Object> conditions);

    /**
     * 获取所有实体列表，按默认排序
     *
     * @return 实体列表，没有记录时返回空列表
     */
    List<T> getAll();

    /**
     * 执行自定义SQL查询
     *
     * @param sql 完整的SQL语句，不能为null或空
     * @param params SQL参数
     * @return 实体列表，没有记录时返回空列表
     */
    List<T> find(String sql, Object... params);

    /**
     * 根据条件查询单个实体
     *
     * @param conditions 查询条件Map
     * @return 实体对象，未找到时返回null
     *
     * 使用示例：
     * <pre>{@code
     * Map<String, Object> conditions = new HashMap<>();
     * conditions.put("username", "admin");
     * conditions.put("status", 1);
     * User user = userService.findOne(conditions);
     * }</pre>
     */
    T findOne(Map<String, Object> conditions);

    /**
     * 根据条件查询实体列表
     *
     * @param conditions 查询条件Map
     * @param orderBy 排序字段，为null时使用默认排序
     * @return 实体列表，没有记录时返回空列表
     */
    List<T> findList(Map<String, Object> conditions, String orderBy);

    /**
     * 根据条件查询实体列表，使用默认排序
     *
     * @param conditions 查询条件Map
     * @return 实体列表，没有记录时返回空列表
     */
    List<T> findList(Map<String, Object> conditions);

    // ========== 存在性检查和统计 ==========

    /**
     * 检查指定主键的实体是否存在
     *
     * @param id 主键值
     * @return 存在返回true，不存在或参数错误返回false
     */
    boolean existsById(Object id);

    /**
     * 检查指定复合主键的实体是否存在
     *
     * @param ids 主键值数组
     * @return 存在返回true，不存在或参数错误返回false
     */
    boolean existsByIds(Object... ids);

    /**
     * 检查指定字段值是否存在
     *
     * @param field 字段名
     * @param value 字段值
     * @return 存在返回true，不存在或参数错误返回false
     *
     * 使用示例：
     * <pre>{@code
     * // 检查用户名是否已存在
     * boolean exists = userService.existsByField("username", "admin");
     * }</pre>
     */
    boolean existsByField(String field, Object value);

    /**
     * 获取实体总数量
     *
     * @return 实体数量，异常时返回0
     */
    long getCount();

    /**
     * 根据条件获取实体数量
     *
     * @param conditions 查询条件
     * @return 满足条件的实体数量
     */
    long getCountByConditions(Map<String, Object> conditions);

    /**
     * 检查字段值是否唯一
     *
     * @param field 要检查的字段名
     * @param value 要检查的字段值
     * @param excludeIds 要排除的主键值（用于更新操作）
     * @return 唯一返回true，不唯一返回false
     *
     * 使用示例：
     * <pre>{@code
     * // 注册时检查邮箱唯一性
     * boolean unique = userService.isFieldUnique("email", "test@example.com");
     *
     * // 更新时检查邮箱唯一性（排除当前用户）
     * boolean unique = userService.isFieldUnique("email", "new@example.com", 1L);
     * }</pre>
     */
    boolean isFieldUnique(String field, Object value, Object... excludeIds);

    /**
     * 获取第一条记录
     *
     * @return 第一条记录的实体对象，没有记录时返回null
     */
    T findFirst();

    /**
     * 获取最后一条记录
     *
     * @return 最后一条记录的实体对象，没有记录时返回null
     */
    T findLast();

    /**
     * 获取基本信息（轻量级查询）
     *
     * @param id 主键值
     * @return 只包含基本字段的实体
     */
    T getBasicInfoById(Object id);

    /**
     * 获取基本信息（轻量级查询）
     *
     * @param ids 主键值数组
     * @return 只包含基本字段的实体
     */
    T getBasicInfoByIds(Object... ids);
}